const fp = require('lodash/fp');

// IO 函子内部封装的值是一个函数，把不纯的操作封装到这个函数，不纯的操作交给调用者处理
class IO {
  // IO函子的of静态方法 将要处理的值 通过匿名函数的方式 存到返回IO实例的_val中
  static of(x) {
    return new IO(function () { return x });
  }
  constructor(fn) {
    this._val = fn;
  }

  // IO函子的map方法则不能如同其他函子一样 使用of方法获取新的函子 
  // 必须用new IO的方式 原因是 如果用of的方法返回新的函子
  // 那么新函子的_val是一个匿名函数 返回值是合并后的函数 
  //  => this._val = funtion() {return fp.flowRight(fn, this._val)}
  // 而我们期望的 是 返回一个新的函子 其内部的_val是合并后的函数
  // => this._val = fp.flowRight(fn, this._val)
  map(fn) {
    return new IO(fp.flowRight(fn, this._val));
  }
}

let r = IO.of(5).map(x => x * x);
console.log(r._val());
// 步骤分析
// 1. IO.of(5) 生产了一个IO函子 里面的_val = function() {return 5};
// 2. .map(x => x*x) 返回了一个新的函子 
//    里面的_val = fp.flowRight(x => x*x, function() {return 5});
// 3. r._val() 就是执行了上面那个函数 
//    先调用function() {return 5}返回5传入x => x*x 返回25 